<?php

namespace tmcore\services\crud\generators;

use app\common\model\dict\DictType;
use tmcore\services\crud\UtilService;

class VueEditView extends Generate
{
    /**
     * @var string
     */
    protected string $fileType = 'vue';

    /**
     * 替换变量
     */
    public function replaceContent()
    {
        $search = [
            '{TEMPLATE_HEADER}',
            '{FORM_VIEW}',
            '{TEMPLATE_FOOTER}',
            '{CAMEL_CLASS_NAME}',
            '{JS_USE}',
            '{JS_HEADER}',
            '{PK}',
            '{FORM_DATA}',
            '{JS_FORM_APPEND}',
            '{FORM_VALIDATE}',
            '{JS_FORM_SUBMIT}',
            '{FORM_APPEND_FOREACH}',
            '{JS_FOOTER}',
            '{JS_EMIT}',
            '{JS_EXPOSE}'
        ];

        $replace = [
            $this->getTemplateHeaderContent(),
            $this->getFormViewContent(),
            $this->getTemplateFooterContent(),
            UtilService::lcfirst($this->getCamelClassName()),
            $this->getJsUseContent(),
            $this->getJsHeaderContent(),
            $this->getPk(),
            $this->getFormDataContent(),
            $this->getJsFromAppendContent(),
            $this->getFormValidateContent(),
            $this->getJsFormSubmitContent(),
            $this->getFormAppendForeachContent(),
            $this->getJsFormFooterContent(),
            $this->getJsEmitContent(),
            $this->getJsExposeContent()
        ];

        $content = UtilService::replaceFileContent($search, $replace, $this->getStub('edit'));

        $this->setContent($content);
    }

    /**
     * 返回模板路径
     * @param string $type
     * @return mixed|string|string[]
     */
    public function getStub(string $type = 'edit')
    {
        $basePath = 'vue/views/';

        $stubs = [
            'form_input' => $this->getTplPath($basePath . 'form/input'),
            'form_textarea' => $this->getTplPath($basePath . 'form/textarea'),
            'form_number' => $this->getTplPath($basePath . 'form/number'),
            'form_select' => $this->getTplPath($basePath . 'form/select'),
            'form_radio' => $this->getTplPath($basePath . 'form/radio'),
            'form_checkbox' => $this->getTplPath($basePath . 'form/checkbox'),
            'form_datePicker' => $this->getTplPath($basePath . 'form/datePicker'),
            'form_timePicker' => $this->getTplPath($basePath . 'form/timePicker'),
            'form_imageSelect' => $this->getTplPath($basePath . 'form/imageSelect'),
            'form_videoSelect' => $this->getTplPath($basePath . 'form/videoSelect'),
            'form_fileSelect' => $this->getTplPath($basePath . 'form/fileSelect'),
            'form_userSelect' => $this->getTplPath($basePath . 'form/userSelect'),
            'form_areaSelect' => $this->getTplPath($basePath . 'form/areaSelect'),
            'form_editor' => $this->getTplPath($basePath . 'form/editor'),
            'form_treeSelect' => $this->getTplPath($basePath . 'form/treeSelect'),
            'page_templateHeaderDialog' => $this->getTplPath($basePath . 'page/edit/templateHeaderDialog'),
            'page_templateFooterDialog' => $this->getTplPath($basePath . 'page/edit/templateFooterDialog'),
            'page_templateHeaderPage' => $this->getTplPath($basePath . 'page/edit/templateHeaderPage'),
            'page_templateFooterPage' => $this->getTplPath($basePath . 'page/edit/templateFooterPage'),
            'page_templateHeaderDrawer' => $this->getTplPath($basePath . 'page/edit/templateHeaderDrawer'),
            'page_templateFooterDrawer' => $this->getTplPath($basePath . 'page/edit/templateFooterDrawer'),
            'edit' => $this->getTplPath($basePath . 'edit'),
        ];

        return $type ? $stubs[$type] : $stubs;
    }

    /**
     * 设置文件路径
     */
    public function setFilePath()
    {
        $name = 'edit.' . $this->fileType;
        $this->setCrudFileName($name);

        $module_path = dirname($this->rootPath) . '/admin/src/views/';
        if (!empty($this->classDir)) $module_path .= $this->classDir . '/';
        $module_path .= UtilService::lcfirst($this->getCamelClassName()) . '/component/';
        $this->setCrudModuleFilePath($module_path);

        $data_path = $this->crudDir . 'vue/src/views/';
        if (!empty($this->classDir)) $data_path .= $this->classDir . '/';
        $data_path .= UtilService::lcfirst($this->getCamelClassName()) . '/component/';
        $this->setCrudDataFilePath($data_path);
    }

    /**
     * 获取模板顶部
     * @return string
     */
    public function getTemplateHeaderContent()
    {
        $tpl_arr = ['Dialog', 'Page', 'Drawer'];
        return file_get_contents($this->getStub('page_templateHeader' . $tpl_arr[($this->crudData['component_type'] - 1)]));
    }

    /**
     * 获取表单内容
     * @return string
     */
    public function getFormViewContent()
    {
        $content = '';
        $tab2 = UtilService::tab(2);
        foreach ($this->crudColumn as $key => $value) {
            if (($value['is_insert'] || $value['is_update']) && !$value['is_pk']) {
                $search = [
                    '{COLUMN_COMMENT}',
                    '{COLUMN_NAME}',
                    '{FOREACH_DATA}',
                ];

                $foreach_content = '';

                if($value['dict_type']) {
                    $dict_type = DictType::where(['id' => $value['dict_type']])->value('value');
                    if($value['view_type'] == 'select') {
                        $foreach_content = <<<CONTENT
{$tab2}<el-option 
{$tab2}    v-for="(item, index) in dictDataList.{$dict_type}"
{$tab2}    :key="index" 
{$tab2}    :label="item.name"
{$tab2}    :value="item.value"
{$tab2}/>
CONTENT;
                    } elseif ($value['view_type'] == 'radio') {
                        $foreach_content = <<<CONTENT
{$tab2}<el-radio 
{$tab2}    v-for="(item, index) in dictDataList.{$dict_type}"
{$tab2}    :key="index"
{$tab2}    :label="item.value"
{$tab2}>
{$tab2}    {{ item.name }}
{$tab2}</el-radio>
CONTENT;
                    } elseif ($value['view_type'] == 'checkbox') {
                        $foreach_content = <<<CONTENT
{$tab2}<el-checkbox
{$tab2}    v-for="(item, index) in dictDataList.{$dict_type}"
{$tab2}    :key="index"
{$tab2}    :label="item.value"
{$tab2}>
{$tab2}    {{ item.name }}
{$tab2}</el-checkbox>
CONTENT;
                    }
                } else {
                    if(!empty($value['extra']['list'])) {
                        foreach ($value['extra']['list'] as $k => $val) {
                            $label_fix = is_numeric($val['value'])?':':'';
                            if($value['view_type'] == 'select') {
                                $foreach_content .= <<<CONTENT
{$tab2}<el-option label="{$val['name']}" value="{$val['value']}" />
CONTENT. PHP_EOL;
                            } elseif ($value['view_type'] == 'radio') {
                                $foreach_content .= <<<CONTENT
{$tab2}<el-radio {$label_fix}label="{$val['value']}">{$val['name']}</el-radio>
CONTENT. PHP_EOL;
                            } elseif ($value['view_type'] == 'checkbox') {
                                $foreach_content .= <<<CONTENT
{$tab2}<el-checkbox {$label_fix}label="{$val['value']}">{$val['value']}</el-checkbox>
CONTENT. PHP_EOL;
                            }
                        }
                        $foreach_content = substr($foreach_content, 0, -1);
                    }
                }

                $replace = [
                    $this->getTableColumnComment($value['column_comment']),
                    $value['column_name'],
                    $foreach_content
                ];

                $viewType = $value['view_type'];

                // 数字输入框
                if ($viewType == 'number') {
                    array_push($search, '{MIN}', '{MAX}');
                    array_push($replace, $value['extra']['min'] ?? 0, $value['extra']['max'] ?? 99999);
                }

                // 文本输入框
                if ($viewType == 'input') {
                    array_push($search, '{PASSWORD}');
                    if(!empty($value['extra']['is_password'])) {
                        array_push($replace, 'type="password" show-password ');
                    } else {
                        array_push($replace, ' ');
                    }
                }

                // 选择器
                if ($viewType == 'select') {
                    array_push($search, '{MULTIPLE}');
                    array_push($replace, empty($value['extra']['multiple']) ? '' : 'multiple');
                }

                // 图片选择器
                if ($viewType == 'imageSelect') {
                    array_push($search, '{LIMIT_COUNT}', '{IS_DIALOG}', '{PROMPT_TEXT}');
                    $limit_count = $value['extra']['limit_count'] ?? 1;
                    array_push($replace, $limit_count, $value['extra']['is_dialog'] ?? 1, $limit_count > 1 ? '最多上传' . $limit_count . '张图片' : '');
                }

                // 文件选择器
                if ($viewType == 'fileSelect') {
                    array_push($search, '{LIMIT_COUNT}', '{IS_DIALOG}', '{PROMPT_TEXT}');
                    $limit_count = $value['extra']['limit_count'] ?? 1;
                    array_push($replace, $limit_count, $value['extra']['is_dialog'] ?? 1, $limit_count > 1 ? '最多上传' . $limit_count . '个文件' : '');
                }

                // 视频选择器
                if ($viewType == 'videoSelect') {
                    array_push($search, '{LIMIT_COUNT}', '{IS_DIALOG}', '{PROMPT_TEXT}');
                    $limit_count = $value['extra']['limit_count'] ?? 1;
                    array_push($replace, $limit_count, $value['extra']['is_dialog'] ?? 1, $limit_count > 1 ? '最多上传' . $limit_count . '个视频' : '');
                }

                // 树状结构选择器
                if ($this->isTypeTree() && $value['column_name'] == $this->treeConfig['tree_pid']) {
                    $viewType = 'treeSelect';
                    array_push($search, '{TREE_ID}', '{TREE_NAME}');
                    array_push($replace, $this->treeConfig['tree_id'], $this->treeConfig['tree_name']);
                }

                // 用户信息选择器
                if ($viewType == 'userSelect') {
                    array_push($search, '{LIMIT_COUNT}', '{PROMPT_TEXT}', '{DEFAULT_VALUE}');
                    $limit_count = $value['extra']['limit_count'] ?? 1;
                    array_push($replace, $limit_count, $limit_count > 1 ? '最多选择' . $limit_count . '个用户' : '', 'formAppendData.' . $value['column_name'] . '_' . UtilService::lower($this->attrPrefix));
                }

                $content .= UtilService::setBlankSpace(UtilService::replaceFileContent($search, $replace, $this->getStub('form_' . $viewType)), '            ') . PHP_EOL;
            }
        }

        if ($content) $content = substr($content, 0, -1);

        return $content;
    }

    /**
     * 获取模板底部
     * @return false|string
     */
    public function getTemplateFooterContent()
    {
        $tpl_arr = ['Dialog', 'Page', 'Drawer'];
        return file_get_contents($this->getStub('page_templateFooter' . $tpl_arr[($this->crudData['component_type'] - 1)]));
    }

    /**
     * 获取JS_USE内容
     * @return string
     */
    public function getJsUseContent()
    {
        $content = '';

        // 检验新页面
        if ($this->crudData['component_type'] == 2) {
            $content .= <<<CONTENT
import { useRoute, useRouter } from 'vue-router';
import useTagsView from '/@/hooks/useTagsView';
CONTENT. PHP_EOL;
        }

        // 关联数据字典
        if (!empty($this->params['crud_column_check']['is_dict'])) {
            $content .= <<<CONTENT
import { crudDictDataList } from '/@/api/crud/table';
CONTENT. PHP_EOL;
        }

        // 检验是否时间戳存储
        if (!empty($this->params['crud_column_check']['is_edit_datePicker'])) {
            $content .= <<<CONTENT
import { dateToString, isNumber } from "/@/utils/util";
CONTENT. PHP_EOL;
        }

        // 拼接api调用
        $apiClass = UtilService::lcfirst($this->crudData['class_name']);

        $apiContent = '{ ' . $apiClass . 'Detail';
        if ($this->crudData['is_insert']) $apiContent .= ', ' . $apiClass . 'Add';
        if ($this->crudData['is_update']) $apiContent .= ', ' . $apiClass . 'Edit';
        if ($this->isTypeTree()) $apiContent .= ', ' . $apiClass . 'All';
        $apiContent .= ' }';

        $apiDir = UtilService::lower($this->classDir) . ($this->classDir ? '/' : '') . UtilService::lcfirst($this->crudData['class_name']);

        $content .= <<<CONTENT
import {$apiContent} from '/@/api/{$apiDir}';
CONTENT;

        return $content;
    }

    /**
     * 获取JS_HEADER内容
     * @return string
     */
    public function getJsHeaderContent()
    {
        $content = '';

        $tpl_arr = ['dialog', 'page', 'drawer'];
        $tpl_type = $tpl_arr[($this->crudData['component_type'] - 1)];

        if ($this->crudData['is_insert']) {
            $default_type = 'add';
        } else {
            $default_type = 'edit';
        }

        // 检测模态框或抽屉
        if ($this->crudData['component_type'] == 1 || $this->crudData['component_type'] == 3) {
            $content .= <<<CONTENT
const {$tpl_type}Ref = ref(null);
CONTENT. PHP_EOL . PHP_EOL;
        }

        if ($this->crudData['is_update'] && (!$this->crudData['is_insert'])) {
            $title_content = "'编辑{$this->crudData['table_comment']}';";
        } elseif ($this->crudData['is_insert'] && (!$this->crudData['is_update'])) {
            $title_content = "'添加{$this->crudData['table_comment']}';";
        } else {
            $title_content = "{$tpl_type}Type.value == 'add' ? '添加{$this->crudData['table_comment']}' : '编辑{$this->crudData['table_comment']}';";
        }
        $tab1 = UtilService::tab(1);

        //拼接标题
        $content .= <<<CONTENT
const {$tpl_type}Type = ref('{$default_type}');

const {$tpl_type}Title = computed(() => {
{$tab1}return {$title_content}
});
CONTENT. PHP_EOL . PHP_EOL;

        // 检测模态框或抽屉
        if ($this->crudData['component_type'] == 1 || $this->crudData['component_type'] == 3) {
            $content .= <<<CONTENT
const emit = defineEmits(['submit', 'close']);
CONTENT. PHP_EOL . PHP_EOL;
        }

        // 检验新页面
        if ($this->crudData['component_type'] == 2) {
            $content .= <<<CONTENT
const route = useRoute();
const router = useRouter();

const { removeTagsView } = useTagsView();
CONTENT. PHP_EOL . PHP_EOL;
        }

        // 关联数据字典
        if (!empty($this->params['crud_column_check']['is_dict'])) {
            $dict_params = '';
            foreach ($this->crudColumn as $value) {
                if ($value['dict_type'] && ($value['is_insert'] || $value['is_update'])) {
                    $dict_params .= ($value['dict_type'] . '@' . $value['column_name'] . ',');
                }
            }
            if ($dict_params) {
                $dict_params = substr($dict_params, 0, -1);

                $content .= <<<CONTENT
const dictDataList = ref({});

const getDictList = async () => {
{$tab1}dictDataList.value = await crudDictDataList({dict_types:'{$dict_params}'});
};
CONTENT . PHP_EOL . PHP_EOL;
            }
        }

        if($this->isTypeTree() && !empty($this->treeConfig['tree_id'])) {
            $apiClass = UtilService::lcfirst($this->crudData['class_name']);
            $content .= <<<CONTENT
const treeList = ref([]);

// 获取树列表
const getTreeList = async () => {
	treeList.value = await {$apiClass}All();
};
CONTENT . PHP_EOL . PHP_EOL;
        }

        $content = substr($content, 0, -2);

        return $content;
    }

    /**
     * 获取表单默认字段内容
     * @return string
     */
    public function getFormDataContent()
    {
        $content = '';
        $tab1 = UtilService::tab(1);
        $intFieldValue = ['tinyint', 'smallint', 'mediumint', 'int', 'integer', 'bigint'];

        foreach ($this->crudColumn as $key => $value) {
            if (($value['is_insert'] || $value['is_update']) && !$value['is_pk']) {
                $default_value = "''";
                if (in_array($value['column_type'], $intFieldValue)) $default_value = 0;
                if ($value['view_type'] == 'checkbox' || ($value['view_type'] == 'select' && !empty($value['extra']['multiple'])) || $value['view_type'] == 'areaSelect') {
                    $default_value = "[]";
                }
                if($value['view_type'] == 'radio' && !empty($value['extra']['list'][0])) {
                    $radio_value = $value['extra']['list'][0]['value'];
                    $default_value = is_numeric($radio_value)? $radio_value:"'{$radio_value}'";
                }
                $content .= <<<CONTENT
                {$tab1}$value[column_name]: $default_value,
                CONTENT. PHP_EOL;
            }
        }

        $content = substr($content, 0, -1);

        return <<<CONTENT
{$tab1}{$this->getPk()}: 0,
$content
CONTENT;
    }

    /**
     * 获取JS_FROM_APPEND内容
     * @return string
     */
    public function getJsFromAppendContent()
    {
        if (empty($this->params['crud_column_check']['append_fields']) || empty($this->params['crud_column_check']['is_userSelect'])) return '';

        $content = '';
        $tab1 = UtilService::tab(1);
        $attrPrefix = UtilService::lower($this->attrPrefix);

        foreach ($this->crudColumn as $key => $value) {
            if (isset($this->params['crud_column_check']['append_fields']) && in_array($value['column_name'], $this->params['crud_column_check']['append_fields'])) {
                $default_value = "''";
                if ($value['view_type'] == 'checkbox' || ($value['view_type'] == 'select' && !empty($value['extra']['multiple'])) || $value['view_type'] == 'areaSelect') {
                    $default_value = "[]";
                }
                $content .= <<<CONTENT
                {$tab1}$value[column_name]_$attrPrefix: $default_value,
                CONTENT. PHP_EOL;
            }
        }

        $content = substr($content, 0, -1);

        return PHP_EOL . <<<CONTENT
const formAppendData = reactive({
$content
});
CONTENT . PHP_EOL;
    }

    /**
     * 获取JS_FROM_APPEND_FOREACH循环内容
     * @return string
     */
    public function getFormAppendForeachContent()
    {
        if (empty($this->params['crud_column_check']['append_fields']) || empty($this->params['crud_column_check']['is_userSelect'])) return '';
        $content = PHP_EOL;
        $is_date = false;

        foreach ($this->crudColumn as $key => $value) {
            if (($value['is_insert'] || $value['is_update']) && !$value['is_pk']) {
                if ($value['view_type'] != 'datePicker' && $value['view_type'] != 'timePicker') {
                    continue;
                }
                $is_date = true;
                $content .= 'formData.' . $value['column_name'] . ' = ' . 'formData.' . $value['column_name'] . ' && isNumber(formData.' . $value['column_name'] . ') ? dateToString(formData.' . $value['column_name'] . ',' . "'yyyy-mm-dd hh:MM:ss'" . ') : String(formData.' . $value['column_name'] . '??"");' . PHP_EOL;
            }
        }

        if($is_date) $content .= PHP_EOL;

        $content .= <<<CONTENT
for (const key in formAppendData) {
    if (data[key] != null && data[key] != undefined) {
        formAppendData[key] = data[key];
    }
}
CONTENT;
        $content = UtilService::setBlankSpace($content, '    ') . PHP_EOL;

        return $content;
    }

    /**
     * 表单验证内容
     * @return string
     */
    public function getFormValidateContent()
    {
        $content = '';
        $tab1 = UtilService::tab(1);

        $view_arr = ['input', 'textarea', 'number', 'editor' ];

        foreach ($this->crudColumn as $key => $value) {
            if (($value['is_insert'] || $value['is_update']) && $value['is_required']) {
                $txt = in_array($value['view_type'], $view_arr)?"输入":"选择";
                $content .= <<<CONTENT
                {$tab1}$value[column_name]: [{ required: true, message: '请{$txt}{$this->getTableColumnComment($value['column_comment'])}', trigger: ['blur'] }],
                CONTENT. PHP_EOL;
            }
        }

        $content = substr($content, 0, -1);

        return <<<CONTENT
$content
CONTENT;
    }

    /**
     * 获取JS提交内容
     * @return string
     */
    public function getJsFormSubmitContent()
    {
        $content = '';

        if ($this->crudData['is_insert']) {
            $default_type = 'add';
        } else {
            $default_type = 'edit';
        }

        $apiClass = UtilService::lcfirst($this->crudData['class_name']);
        $apiContent = '';

        if($this->crudData['component_type'] == 1) {
            $title_type = 'dialogType';
        } elseif ($this->crudData['component_type'] == 2) {
            $title_type = 'pageType';
        } else {
            $title_type = 'drawerType';
        }

        if ($this->crudData['is_insert'] && $this->crudData['is_update']) {
            $apiContent = "{$title_type}.value == '{$default_type}' ? await {$apiClass}Add(formData) : await {$apiClass}Edit(formData);";
        } elseif ($this->crudData['is_insert'] && !$this->crudData['is_update']) {
            $apiContent = "await {$apiClass}Add(formData);";
        } elseif (!$this->crudData['is_insert'] && $this->crudData['is_update']) {
            $apiContent = "await {$apiClass}Edit(formData)";
        }

        $tab2 = UtilService::tab(2);

        $content .= <<<CONTENT
$apiContent
CONTENT. PHP_EOL;

        if ($this->crudData['component_type'] == 1) {
            $content .= <<<CONTENT
{$tab2}dialogRef.value?.close();
{$tab2}emit('submit');
CONTENT. PHP_EOL;
        } elseif ($this->crudData['component_type'] == 2) {
            $content .= <<<CONTENT
{$tab2}removeTagsView();
{$tab2}router.back();
CONTENT. PHP_EOL;
        } elseif ($this->crudData['component_type'] == 3) {
            $content .= <<<CONTENT
{$tab2}drawerRef.value?.close();
{$tab2}emit('submit');
CONTENT. PHP_EOL;
        }

        $content = substr($content, 0, -1);

        return $content;
    }

    /**
     * 获取JS尾部内容
     * @return string
     */
    public function getJsFormFooterContent()
    {
        $content = '';

        if($this->crudData['component_type'] == 2) {
            if ($this->crudData['is_insert'] && $this->crudData['is_update']) {
                $content = <<<CONTENT
if (route.query.id) {
    pageType.value = 'edit';
    setFormData({{$this->getPk()}:route.query.{$this->getPk()}}, null);
} else {
    pageType.value = 'add';
}
CONTENT;
            } elseif ($this->crudData['is_insert'] && !$this->crudData['is_update']) {
                $content = <<<CONTENT
pageType.value = 'add';
CONTENT;
            } elseif (!$this->crudData['is_insert'] && $this->crudData['is_update']) {
                $content = <<<CONTENT
if (route.query.id) {
    pageType.value = 'edit';
    setFormData({{$this->getPk()}:route.query.{$this->getPk()}}, null);
}
CONTENT;
            }

        }

        if($this->isTypeTree()) {
            if($content) $content .= PHP_EOL;
            $content .=  <<<CONTENT
getTreeList();
CONTENT;
        }

        if($content) $content = UtilService::setBlankSpace($content, '    ');

        return $content;
    }

    /**
     * 获取JS_EMIT内容
     * @return string
     */
    public function getJsEmitContent() {
        $content = '';

        if ($this->crudData['is_insert']) {
            $default_type = 'add';
        } else {
            $default_type = 'edit';
        }

        $tpl_arr = ['dialog', 'page', 'drawer'];
        $tpl_type = $tpl_arr[($this->crudData['component_type'] - 1)];
        if ($this->crudData['component_type'] == 1 || $this->crudData['component_type'] == 3) {
            $content .= PHP_EOL;
            $content .= <<<CONTENT
const handleClose = () => {
	emit('close');
};

const open = (type = '{$default_type}') => {
	{$tpl_type}Type.value = type;
	{$tpl_type}Ref.value?.open();
};
CONTENT. PHP_EOL;
        }

        return $content;
    }

    /**
     * 获取JS_EXPOSE内容
     * @return string
     */
    public function getJsExposeContent() {
        $content = '';

        if ($this->crudData['component_type'] == 1 || $this->crudData['component_type'] == 3) {
            $content .= PHP_EOL;
            $content .= <<<CONTENT
defineExpose({
	open,
	setFormData,
});
CONTENT. PHP_EOL;
        }

        return $content;
    }

}